#pragma once

#include "Request.h"
#include "../common/Common.h"

namespace rpc
{
    namespace client
    {

        class RpcCaller
        {
        public:
            using ptr = std::shared_ptr<RpcCaller>;
            using JsonAsyncResponse = future<Json::Value>;
            using JsonResponseCallback = std::function<void(const Json::Value &)>;

            RpcCaller(const Request::ptr &req) : _request(req) {}

            // requestor中的处理是针对BaseMessage进行处理的
            // 用于在rpccaller中针对结果的处理是针对 RpcResponse里边的result进行的
            bool call(const BaseConnection::ptr &conn, const string &method, const Json::Value &params, Json::Value &result)
            {
                DLOG("开始同步rpc调用...");
                // 1. 组织请求
                auto req = MessageFactory::create<RpcRequest>();
                req->setRid(uuid());
                req->setMethod(method);
                req->setParams(params);
                req->setMtype(MType::REQ_RPC);

                BaseMessage::ptr resp;
                // 2. 发送请求
                if (!_request->send(conn, req, resp))
                {
                    ELOG("同步rpc请求调用失败");
                    return false;
                }

                DLOG("收到响应，进行解析，获取结果!");
                // 3. 等待响应
                auto rpcResp = std::dynamic_pointer_cast<RpcResponse>(resp);
                if (!rpcResp)
                {
                    ELOG("rpc响应，向下转型失败！");
                    return false;
                }

                if (rpcResp->rcode() != RCode::RCODE_OK)
                {
                    ELOG("rpc请求出错：%s", errReason(rpcResp->rcode()).c_str());
                    return false;
                }

                result = rpcResp->result();
                DLOG("结果设置完毕");
                return true;
            }

            bool call(const BaseConnection::ptr &conn, const string &method, const Json::Value &params, JsonAsyncResponse &result)
            {
                RpcRequest::ptr req = MessageFactory::create<RpcRequest>();
                req->setMethod(method);
                req->setMtype(MType::REQ_RPC);
                req->setParams(params);
                req->setRid(uuid());

                std::shared_ptr<promise<Json::Value>> asyncResp = std::make_shared<promise<Json::Value>>();
                result = asyncResp->get_future();

                Request::RequestCallback cb = std::bind(&RpcCaller::callback, this, asyncResp, _1);
                if (!_request->send(conn, req, cb))
                {
                    ELOG("异步请求失败");
                    return false;
                }

                return true;
            }

            bool call(const BaseConnection::ptr &conn, const string &method, const Json::Value &params, const JsonResponseCallback &cb)
            {
                RpcRequest::ptr req = MessageFactory::create<RpcRequest>();
                req->setMethod(method);
                req->setMtype(MType::REQ_RPC);
                req->setParams(params);
                req->setRid(uuid());

                auto reqCb = std::bind(&RpcCaller::callback1, this, cb, _1);
                if (!_request->send(conn, req, reqCb))
                {
                    ELOG("rpc回调请求失败");
                    return false;
                }

                return true;
            }

        private:
            void callback1(const JsonResponseCallback &cb, const BaseMessage::ptr &resp)
            {
                auto rpcResp = std::dynamic_pointer_cast<RpcResponse>(resp);
                if (!rpcResp)
                {
                    ELOG("rpc响应，向下转型失败");
                    return;
                }

                if (rpcResp->rcode() != RCode::RCODE_OK)
                {
                    ELOG("rpc异步请求出错 %s", errReason(rpcResp->rcode()).c_str());
                    return;
                }

                cb(rpcResp->result());
            }

            void callback(const std::shared_ptr<promise<Json::Value>> promise, const BaseMessage::ptr &resp)
            {
                auto rpcResp = std::dynamic_pointer_cast<RpcResponse>(resp);
                if (!rpcResp)
                {
                    ELOG("rpc响应，向下转型失败");
                    return;
                }

                if (rpcResp->rcode() != RCode::RCODE_OK)
                {
                    ELOG("rpc异步请求出错 %s", errReason(rpcResp->rcode()).c_str());
                    return;
                }
                promise->set_value(rpcResp->result());
            }

        private:
            Request::ptr _request;
        };

    };
};